package com.yuntsg.nnsfcp.test.bosspdfparsetest;

import cn.hutool.core.util.NumberUtil;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Util {


    // 获取附件部分
    public static int getAnnexField(int i, List<En.TableText> l, int number, List<En.Annex> annexList) {
        String a = l.get(i).getText();
        String b = (l.size() > i + 1) ? l.get(i + 1).getText() : "_|~b=|_";
        String c = (l.size() > i + 2) ? l.get(i + 2).getText() : "_|~c=|_";
        String d = (l.size() > i + 3) ? l.get(i + 3).getText() : "_|~d=|_";
        if ("序号".equals(a) && "附件名称".equals(b) && "备注".equals(c) && "附件类型".equals(d)) {
            String serialNumber = ""; // 序号
            StringBuilder annexName = new StringBuilder(); // 附件名称
            StringBuilder notes = new StringBuilder(); // 备注
            StringBuilder annexType = new StringBuilder(); // 附件类型
            boolean isSerialNumber = false;
            for (int j = i + number; j < l.size(); j++) {
                String t = l.get(j).getText();
                float left = l.get(j).getLeft();
                if ("项目名称：".equals(t)) {
                    if (!serialNumber.isEmpty()) {
                        En.Annex annex = new En.Annex();
                        annex.setSerialNumber(serialNumber);
                        annex.setAnnexName(annexName.toString());
                        annex.setNotes(notes.toString());
                        annex.setAnnexType(annexType.toString());
                        annexList.add(annex);
                    }
                    return j;
                } else {
                    if (NumberUtil.isInteger(t.trim()) && left > 74 && left < 110) {
                        isSerialNumber = true;
                        if (!serialNumber.isEmpty()) {
                            En.Annex annex = new En.Annex();
                            annex.setSerialNumber(serialNumber.trim());
                            annex.setAnnexName(annexName.toString().trim());
                            annex.setNotes(notes.toString().trim());
                            annex.setAnnexType(annexType.toString().trim());
                            annexList.add(annex);
                            annexName = new StringBuilder(); // 附件名称
                            notes = new StringBuilder(); // 备注
                            annexType = new StringBuilder(); // 附件类型
                        }
                        serialNumber = t;
                    } else if (isSerialNumber) {
                        if (left > 109 && left < 252) {
                            annexName.append(t);
                        }
                        if (left > 251 && left < 394) {
                            notes.append(t);
                        }
                        if (left > 393) {
                            annexType.append(t);
                        }
                    }
                }
            }
        }
        return i;
    }

    // 获取简历部分
    public static int getResume(int i, List<En.TableText> l, String t, List<En.Resume> resumeList) {
        if ("2024版".equals(t)) {
            Map<String, String> labelAndInfoMap = new HashMap<>();
            for (int j = i; j < l.size(); j++) {
                String f = l.get(j).getText();
                if ("附件信息".equals(f)) {
                    String m = (l.size() > j + 1) ? l.get(j + 1).getText() : "_|~m=|_";
                    String e = (l.size() > j + 2) ? l.get(j + 2).getText() : "_|~e=|_";
                    if ("序号".equals(m) && "附件名称".equals(e)) {
                        return j;
                    }
                }
                j = getResumeField(j, l, " 简历", labelAndInfoMap, "name", 1);
                j = getResumeField(j, l, "教育经历：", labelAndInfoMap, "unit", 1);
                j = getResumeField(j, l, "博士后工作经历：", labelAndInfoMap, "education", 1);
                j = getResumeField(j, l, "科研与学术工作经历（博士后工作经历除外）：", labelAndInfoMap, "work", 1);
                j = getResumeField(j, l, "曾使用其他证件信息：", labelAndInfoMap, "scientific", 1);
                j = getResumeField(j, l, "近五年主持或参加的国家自然科学基金项目/课题：", labelAndInfoMap, "document", 1);
                j = getResumeField(j, l, "近五年主持或参加的其他科研项目/课题（国家自然科学基金项目除外）：", labelAndInfoMap, "fund", 1);
                j = getResumeField(j, l, "代表性研究成果和学术奖励情况（填写代表性论文时应根据其发表时的真实情况如实规范列", labelAndInfoMap, "project", 1);
                j = getResumeField(j, l, "二、论著之外的代表性研究成果和学术奖励：", labelAndInfoMap, "representative", 5);
                j = getResumeField(j, l, "2024版", labelAndInfoMap, "publication", 1) - 1;
                En.Resume resume = new En.Resume();
                for (Map.Entry<String, String> entry : labelAndInfoMap.entrySet()) {
                    String label = entry.getKey();
                    if ("name".equals(label)) {
                        resume.setName(entry.getValue());
                    }
                    if ("unit".equals(label)) {
                        resume.setUnit(entry.getValue());
                    }
                    if ("education".equals(label)) {
                        resume.setEducation(entry.getValue());
                    }
                    if ("work".equals(label)) {
                        resume.setWork(entry.getValue());
                    }
                    if ("scientific".equals(label)) {
                        resume.setScientific(entry.getValue());
                    }
                    if ("document".equals(label)) {
                        resume.setDocument(entry.getValue());
                    }
                    if ("fund".equals(label)) {
                        resume.setFund(entry.getValue());
                    }
                    if ("project".equals(label)) {
                        resume.setProject(entry.getValue());
                    }
                    if ("representative".equals(label)) {
                        resume.setRepresentative(entry.getValue());
                    }
                    if ("publication".equals(label)) {
                        resume.setPublication(entry.getValue());
                    }
                }
                resumeList.add(resume);
            }
        }
        return i;
    }

    // 获取简历部分内各字段的信息
    public static int getResumeField(int i, List<En.TableText> l, String first, Map<String, String> labelAndInfoMap, String type, int number) {
        StringBuilder s = new StringBuilder();
        for (int j = i + number; j < l.size(); j++) {
            String n = l.get(j).getText();
            String m = (l.size() > j + 1) ? l.get(j + 1).getText() : "_|~m=|_";
            String e = (l.size() > j + 2) ? l.get(j + 2).getText() : "_|~e=|_";
            if (first.equals(n) || ("附件信息".equals(n) && "序号".equals(m) && "附件名称".equals(e))) {
                labelAndInfoMap.put(type, s.toString().trim());
                return j;
            } else {
                if (Pattern.compile("^\\([0-9]{0,2}\\) ").matcher(n).find()) {
                    s.append(System.lineSeparator()).append(n);
                } else {
                    s.append(n);
                }
            }
        }
        return i;
    }

    // 参数：labelSet:标签集合，
    // currentLabel:当前的本次处理后应移除的标签，
    // start:当前的标签出现指定的字符串后开始工作，
    // netLabel:下一个标签，
    // first:本次的标签结束，下一个标签的触发条件，即出现的第一行字符串的值，
    // middle:第二行的值，
    // end:第三行的值。
    // number:本次的内容去掉不需要的行数，
    // labelAndInfoMap:当前的标签及获取的内容保存。
    public static int getReportText(int i, List<En.TableText> l, Set<String> labelSet, String currentLabel, String start, String netLabel, String first, String middle, String end, int number, Map<String, String> labelAndInfoMap) {
        if ((labelSet.contains(currentLabel) || labelSet.isEmpty()) && !labelSet.contains(netLabel)) {
            StringBuilder s = new StringBuilder();
            boolean b = false;
            int sum = 0;
            // 为什么加入布尔b：作用是只有出现指定的字符串start后才开始工作。为什么加入sum：意思是出现指定字符串start后多少行才开始工作，而参数number就是指定的多少行的数字值。
            for (int j = i; j < l.size(); j++) {
                String f = l.get(j).getText();
                b = f.equals(start) || b;
                sum = b ? sum + 1 : sum;
                if (b && sum >= number) {
                    String m = (l.size() > j + 1) ? l.get(j + 1).getText() : "_|~m=|_";
                    String e = (l.size() > j + 2) ? l.get(j + 2).getText() : "_|~e=|_";
                    if ((first.isEmpty() || first.equals(f)) && (middle.isEmpty() || middle.equals(m)) && (end.isEmpty() || end.equals(e))) {
                        labelSet.add(netLabel);
                        labelSet.remove(currentLabel);
                        labelAndInfoMap.put(currentLabel, s.toString().trim());
                        return j;
                    } else {
                        if (" ".equals(f) && !s.toString().endsWith(System.lineSeparator())) {
                            s.append(System.lineSeparator());
                        } else if (!f.replace(" ", "").trim().isEmpty()) {
                            s.append(f);
                        }
                    }
                }
            }
        }
        return i;
    }


    // 17010000003013679本版本用到的字段信息
    public static Set<String> getField17010000003013679() {
        Set<String> set = new HashSet<>();
        set.add("申请代码");
        set.add("受理部门");
        set.add("收件日期");
        set.add("受理编号");
        set.add("资助类别：");
        set.add("亚类说明：");
        set.add("附注说明：");
        set.add("项目名称：");
        set.add("申 请 人：");
        set.add("BRID：");
        set.add("办公电话：");
        set.add("依托单位：");
        set.add("通讯地址：");
        set.add("邮政编码：");
        set.add("单位电话：");
        set.add("电 话：");
        set.add("申报日期：");
        set.add("电子邮箱：");
        set.add("姓        名");
        set.add("性别");
        set.add("出生年月");
        set.add("民族");
        set.add("学        位");
        set.add("职称");
        set.add("是否在站博士后");
        set.add("电子邮箱");
        set.add("办公电话");
        set.add("国别或地区");
        set.add("申请人类别");
        set.add("工   作   单   位");
        set.add("个 人 通 讯 地 址");
        set.add("主 要 研 究 领 域");
        set.add("名        称");
        set.add("联   系   人");
        set.add("电        话");
        set.add("网站地址");
        set.add("单 位 名 称");
        set.add("项目名称");
        set.add("英文名称");
        set.add("资助类别");
        set.add("亚类说明");
        set.add("附注说明");
        set.add("研究期限");
        set.add("研究方向：");
        set.add("申请直接费用");
        set.add("研究属性");
        set.add("中文关键词");
        set.add("英文关键词");
        set.add("中文摘要");
        set.add("英文摘要");
        return set;
    }

    // 本版本用到的字段信息
    public static Set<String> getField() {
        Set<String> set = new HashSet<>();
        set.add("申请代码");
        set.add("接收部门");
        set.add("收件日期");
        set.add("接收编号");
        set.add("资助类别：");
        set.add("亚类说明：");
        set.add("附注说明：");
        set.add("项目名称：");
        set.add("申 请 人：");
        set.add("BRID：");
        set.add("办公电话：");
        set.add("依托单位：");
        set.add("通讯地址：");
        set.add("邮政编码：");
        set.add("单位电话：");
        set.add("电子邮箱：");
        set.add("姓        名");
        set.add("性别");
        set.add("出生年月");
        set.add("民族");
        set.add("学        位");
        set.add("职称");
        set.add("是否在站博士后");
        set.add("电子邮箱");
        set.add("办公电话");
        set.add("国别或地区");
        set.add("申请人类别");
        set.add("工   作   单   位");
        set.add("主 要 研 究 领 域");
        set.add("名        称");
        set.add("联   系   人");
        set.add("电        话");
        set.add("网站地址");
        set.add("单 位 名 称");
        set.add("项目名称");
        set.add("英文名称");
        set.add("资助类别");
        set.add("亚类说明");
        set.add("附注说明");
        set.add("研究期限");
        set.add("研究方向：");
        set.add("申请直接费用");
        set.add("研究属性");
        set.add("中文关键词");
        set.add("英文关键词");
        set.add("中文摘要");
        set.add("英文摘要");
        return set;
    }

    // 判断是否包含中文汉字
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        return m.find();
    }

    // 循环获取字符串。参数isBreak:是否执行换行，比如，中英文摘要有必要换行，但关键词列表没必要换行。add：需要增加的个数，identifier：标识符，比如：英文关键词，意思是表示到些要结束了。
    public static String forGetField(List<En.TableText> tableTextList, int i, boolean isBreak, int add, String identifier) {
        StringBuilder s = new StringBuilder();
        for (int j = i + add; j < tableTextList.size(); j++) {
            String n = tableTextList.get(j).getText();
            if (identifier.equals(n)) {
                break;
            } else {
                if (isBreak && (n.endsWith(".") || n.endsWith(". ") || n.endsWith("。") || n.endsWith("。 "))) {
                    s.append(n).append(System.lineSeparator());
                } else {
                    if (isContainChinese(n)) {
                        s.append(n);
                    } else {
                        s.append(" ").append(n);
                    }
                }
            }
        }
        return s.toString();
    }

    // 删除标书内的页码信息，因为pdf解析不规整，页码信息出现占5，6，7三行这三种。另外，封面和最后两页盖章页也没有页码，需要单独删除。
    public static List<En.TableText> dellPageInfo(File filePath) throws IOException {
        List<En.TableText> list = new ArrayList<>();
        File file = filePath;
        List<En.TableText> tableTextList = getPdfInfo(file);
        for (int i = 0; i < tableTextList.size(); i++) {
            En.TableText tableText = tableTextList.get(i);
            String text = tableText.getText();

            if (text.startsWith("NSF")) {
                if (tableTextList.size() > i + 6 && ("版本：24010314121045058".equals(tableTextList.get(i + 6).getText())) && ("国家自然科学基金申请书".equals(tableTextList.get(i + 4).getText()))) {
                    i = i + 6;
                } else if (tableTextList.size() > i + 5 && ("版本：24010314121045058".equals(tableTextList.get(i + 5).getText())) && ("国家自然科学基金申请书".equals(tableTextList.get(i + 3).getText()))) {
                    i = i + 5;
                } else if (tableTextList.size() > i + 4 && ("版本：24010314121045058".equals(tableTextList.get(i + 4).getText())) && ("国家自然科学基金申请书".equals(tableTextList.get(i + 2).getText()))) {
                    i = i + 4;
                } else {
                    list.add(tableText);
                }
            } else if ("国家自然科学基金申请书".equals(text) && tableTextList.size() > i + 1 && ("2024版".equals(tableTextList.get(i + 1).getText()))) {
                i = i + 1;
            } else {
                list.add(tableText);
            }
        }
        return list;
    }

    public static List<En.TableText> getPdfInfo(File filepath) throws IOException {
//        BufferedInputStream file = FileUtil.getInputStream(filepath);
        File pdffile = filepath;
        PDDocument document = Loader.loadPDF(pdffile);
        List<En.TableText> tableTextList = new ArrayList<>();
        PDFTextStripper reader = new PDFTextStripper() {
            @Override
            protected void writeString(String string, List<TextPosition> textPositions) {
                int page = this.getCurrentPageNo();
                StringBuilder result = new StringBuilder();
                float minLeft = 999999.99f;
                float sumWidth = 0.0f;
                Map<Float, Integer> heightMap = new HashMap<>();
                Map<Float, Integer> topMap = new HashMap<>();
//                List<String> collect = textPositions.stream().map(o -> o.getUnicode().toString()).collect(Collectors.toList());
//                String merge = String.join("", collect);
//                System.out.println("merge+"+merge);
                for (int i = 0; i < textPositions.size(); i++) {
                    // 大体意思根据每个字的坐标进行判断 如果到最后一个则进行停止 清空坐标 进行保存
                    TextPosition position = textPositions.get(i);
                    float width = position.getWidth();
                    float height = position.getHeight();
                    float left = position.getX();
                    float top = position.getY();
                    String unicode = position.getUnicode();
                    minLeft = Math.min(minLeft, left);
                    sumWidth += width;
                    heightMap.compute(height, (key, value) -> value != null ? (value + 1) : 1);
                    topMap.compute(top, (key, value) -> value != null ? (value + 1) : 1);
                    En.FontSize fontSize = new En.FontSize();
                    fontSize.setFont(position.getFont().getName());
                    fontSize.setSize(Math.round(position.getFontSizeInPt()));
                    En.FontSize nextFontSize = new En.FontSize();
                    float nextLeft = 0.0f;
                    if (textPositions.size() > i + 1) {
                        TextPosition nextPosition = textPositions.get(i + 1);
                        nextFontSize.setFont(nextPosition.getFont().getName());
                        nextFontSize.setSize(Math.round(nextPosition.getFontSizeInPt()));
                        nextLeft = nextPosition.getX();
                    }
                    result.append(position.getUnicode());
//                    System.out.println("position.getUnicode()+"+position.getUnicode());
                    float gap = Math.max(Math.abs(nextLeft - left - width), 1.6f);
                    String r = result.toString();
                    boolean a = fontSize.equals(nextFontSize) && (gap > width * 3 && (!r.isEmpty() || " ".equals(unicode)));
                    boolean b = !fontSize.equals(nextFontSize) && !result.toString().isEmpty();
                    boolean c = ("是否在站博士后 ".equals(r) || "研究方向：".equals(r));
                    if (a || b || c) {
                        float mostHeight = Util.getMaxFloat(heightMap);
                        float mostTop = Util.getMaxFloat(topMap);
                        En.TableText tableText = new En.TableText();
                        tableText.setHeight(Util.takeFourDigits(mostHeight));
                        tableText.setTop(Util.takeFourDigits(mostTop));
                        tableText.setWidth(Util.takeFourDigits(sumWidth));
                        tableText.setLeft(Util.takeFourDigits(minLeft));
                        tableText.setPage(page);
                        tableText.setFont(fontSize.getFont());
                        tableText.setSize(fontSize.getSize());
                        tableText.setText(result.toString());
                        sumWidth = 0.0f;
                        minLeft = 999999.99f;
                        result = new StringBuilder();
                        heightMap = new HashMap<>();
                        topMap = new HashMap<>();
                        tableTextList.add(tableText);
                    }
                }
            }
        };
        reader.writeText(document, new OutputStreamWriter(System.out));
        return tableTextList;
    }

    // 如果只有二位，返回最大的，大于二位的，返回出现最多的。
    public static float getMaxFloat(Map<Float, Integer> mapName) {
        int sum = 0;
        float most = 0.0f;
        float max = 0.0f;
        for (Map.Entry<Float, Integer> entry : mapName.entrySet()) {
            if (entry.getValue() > sum) {
                sum = entry.getValue();
                most = entry.getKey();
            }
            max = Math.max(max, entry.getKey());
        }
        if (mapName.size() == 2) {
            return max;
        }
        return most;
    }

    // 取小数点后2位
    public static float takeFourDigits(float d) {
        BigDecimal bd = new BigDecimal(d);
        BigDecimal bd2 = bd.setScale(2, RoundingMode.HALF_UP);
        return Float.parseFloat(bd2.toString());
    }


}